# /app/tsp.py
import numpy as np

from app.map_planner import MapBase


class TSP:
    """TSP算法类"""
    def __init__(self):
        """初始化TSP算法。"""
        self.map_base = MapBase()
        self.distance_matrix = self.map_base.distance_matrix
        self.coordinates = self.map_base.coordinates

    def nearest_neighbor(
            self,
            start_node: int,
            nodes: list
    ) -> list:
        """节点排序。

        Args:
            start_node: 起始节点 1
            nodes: 节点列表 [2, 3, 4, ...]

        Returns:
            list: [起始节点, 最接近的节点, 第二个接近的节点, ...]
        """
        unvisited = set(nodes)
        tour = [start_node]
        current_node = start_node

        while unvisited:
            next_node = min(unvisited, key=lambda node: self.distance_matrix[current_node][node])
            tour.append(next_node)
            unvisited.remove(next_node)
            current_node = next_node

        return tour

    def near_point(
            self,
            start_point: int,
            points: list
    ) -> list:
        """找到最近的节点。

        Args:
            start_point: 待匹配节点 1
            points: 节点列表 [2, 3, 4, ...]

        Returns:
            list: [待匹配节点, 节点列表中最近的节点]
        """
        tour = self.nearest_neighbor(start_point, points)
        good_point = [start_point, tour[1]]
        return good_point
    
    def nearest_neighbor_by_locstr(
            self,
            start_location: str,
            locations: list
    ) -> list:
        """通过坐标进行节点排序。

        Args:
            start_location: 起始 "1,3"
            locations: 节点列表 ["1,1", "2,2", ...]

        Returns:
            list: [起始节点, 最接近的节点, 第二个接近的节点, ...]
        """
        # 起始节点转化为节点ID
        start_loc = self.map_base.find_node_by_locstr(start_location)[1]
        # 节点列表转化为节点ID列表
        locs = self.map_base.locstrs_to_nodes(locations)

        # 进行最近邻算法计算
        tour = self.nearest_neighbor(start_loc, locs)

        # 节点ID列表转化为坐标列表
        tour_str = self.map_base.nodes_to_locstrs(tour)

        return tour_str
    
    def near_point_by_locstr(
            self,
            start_point: str,
            points: list
    ) -> list:
        """通过坐标，找到最近的节点。

        Args:
            start_point: 待匹配节点 '1,3'
            points: 节点列表 ['1,1', '2,2', ...]

        Returns:
            list: [待匹配节点, 节点列表中最近的节点]
        """
        tour = self.nearest_neighbor_by_locstr(start_point, points)
        good_point = [start_point, tour[1]]
        return good_point
    
    def advanced_nearest_neighbor(
            self,
            start_location: str,
            locations: list
    ) -> list:
        """节点排序(改进)。

        Args:
            start_location: 起始 '1,3,1'
            locations: 节点列表 ['1,1,1', '1,4,2', ...]

        Returns:
            list: [最接近的起始节点的第一个节点, 第二个接近的节点, ...]
        """

        # 起始坐标
        start = self.map_base.split_location_by_loc(start_location)['xy']

        # 未排序坐标列表
        unsorted_loc_list = locations
        
        # 未排序坐标字典列表
        unsorted_loc_dict_list = []
        # 未排序无库区号坐标列表
        unsorted_loc_nowhs_list = []
        for location in unsorted_loc_list:
            whs, x, y = location.split(",")
            whs = int(whs)
            loc = f"{x},{y}"
            loc_dict = {
                "whs": whs,
                "loc": loc
            }
            unsorted_loc_nowhs_list.append(loc)
            unsorted_loc_dict_list.append(loc_dict)
        
        # 已排序无库区号坐标列表
        sorted_loc_nowhs_list = self.nearest_neighbor_by_locstr(start, unsorted_loc_nowhs_list)

        # 创建一个顺序映射字典：坐标字符串 -> 排序索引
        # 从排序后的列表中提取从索引1开始（即跳过起点）的坐标和其对应的新索引（从0开始）
        order_mapping = {}
        # 枚举从第二个元素开始（跳过起点）的列表，为其创建从0开始的映射
        for index, loc in enumerate(sorted_loc_nowhs_list[1:]):
            order_mapping[loc] = index

        # 使用映射字典来排序 unsorted_loc_dict_list
        # 使用 .get() 方法，如果某个 x['loc'] 不在映射中，则返回一个很大的值（如 float('inf')），使其排在最后
        sorted_loc_dict_list = sorted(unsorted_loc_dict_list,
                                    key=lambda x: order_mapping.get(x["loc"], float('inf')))
        
        # 已排序坐标列表
        sorted_loc_list = []
        for loc_dict in sorted_loc_dict_list:
            warehouse = loc_dict["whs"]
            loc = loc_dict["loc"]
            sorted_loc = f"{warehouse},{loc}"
            sorted_loc_list.append(sorted_loc)

        return sorted_loc_list

#############################################
# # test_tsp
# # 定义一个距离矩阵
# distance_matrix = np.array([
#     [0, 2, 9, 10],
#     [1, 0, 6, 4],
#     [15, 7, 0, 8],
#     [6, 3, 12, 0]
# ])
# start_node = 0
# nodes = [1, 2, 3]

# # 调用函数
# tour = nearest_neighbor(distance_matrix, start_node, nodes)
# print(f"Node Tist: [{start_node}, {nodes[0]}, {nodes[1]}, {nodes[2]}]")
# print("Computed Tour:", tour)